bl_info = {
    "name": "Merge Same Material Meshes",
    "author": "AI Assistant",
    "version": (1, 0, 0),
    "blender": (4, 2, 0),
    "location": "View3D > Sidebar > Tool",
    "description": "自动合并集合内相同材质的mesh对象",
    "category": "Object",
}

import bpy
import bmesh
from bpy.types import Panel, Operator
from bpy.props import StringProperty


class OBJECT_OT_merge_same_material_meshes(Operator):
    """合并集合内相同材质的mesh对象"""
    bl_idname = "object.merge_same_material_meshes"
    bl_label = "合并同材质Mesh"
    bl_options = {'REGISTER', 'UNDO'}
    
    collection_name: StringProperty(
        name="集合名称",
        description="要处理的集合名称",
        default=""
    )

    def execute(self, context):
        if not self.collection_name:
            self.report({'ERROR'}, "请输入集合名称")
            return {'CANCELLED'}
        
        collection = bpy.data.collections.get(self.collection_name)
        if not collection:
            self.report({'ERROR'}, f"找不到集合: {self.collection_name}")
            return {'CANCELLED'}
        
        # 按材质和类型分组对象
        material_groups = {
            '网格': {},  # 有面的mesh
            '线': {}     # 没有面的mesh
        }
        
        for obj in collection.objects:
            # 只处理网格对象
            if obj.type != 'MESH':
                continue
                
            # 判断是网格还是线
            obj_type = '网格' if len(obj.data.polygons) > 0 else '线'
            material_name = 'NoMaterial'
            has_material = False
            
            if obj.data.materials and len(obj.data.materials) > 0:
                # 检查网格对象实际使用的材质
                used_material_indices = set()
                for face in obj.data.polygons:
                    used_material_indices.add(face.material_index)
                
                if len(used_material_indices) == 1:
                    material_index = next(iter(used_material_indices))
                    if material_index < len(obj.data.materials):
                        material = obj.data.materials[material_index]
                        if material is not None:
                            material_name = material.name
                            has_material = True
            
            # 将对象添加到相应组
            if material_name not in material_groups[obj_type]:
                material_groups[obj_type][material_name] = []
            material_groups[obj_type][material_name].append(obj)
        
        merged_count = 0
        
        # 遍历不同类型的对象
        for obj_type, type_groups in material_groups.items():
            # 遍历每种类型下的材质组
            for material_name, objects in type_groups.items():
                if len(objects) < 2:
                    continue
                    
                # 创建新的网格对象
                new_data = bpy.data.meshes.new(f"{material_name}_{obj_type}_merged")
                new_obj = bpy.data.objects.new(f"{material_name}_{obj_type}_merged", new_data)
                
                # 合并所有网格
                bm = bmesh.new()
                for obj in objects:
                    mesh = obj.data
                    bm.from_mesh(mesh)
                    
                    # 应用变换
                    matrix_world = obj.matrix_world
                    for vert in bm.verts[-len(mesh.vertices):]:
                        vert.co = matrix_world @ vert.co
                
                # 更新网格数据
                bm.to_mesh(new_data)
                bm.free()
                
                # 设置材质
                if material_name != 'NoMaterial':
                    if material_name in bpy.data.materials:
                        new_obj.data.materials.append(bpy.data.materials[material_name])
                    else:
                        self.report({'WARNING'}, f"材质 {material_name} 不存在，无法设置给合并后的对象")
                
                # 添加到集合
                collection.objects.link(new_obj)
                
                # 删除原对象
                for obj in objects:
                    bpy.data.objects.remove(obj, do_unlink=True)
                
                merged_count += 1
                if material_name == 'NoMaterial':
                    self.report({'INFO'}, f"已合并 {obj_type} 类型的无材质对象 {len(objects)} 个")
                else:
                    self.report({'INFO'}, f"已合并 {obj_type} 类型材质 {material_name} 的 {len(objects)} 个对象")
        
        if merged_count == 0:
            self.report({'WARNING'}, "没有可合并的同材质mesh对象")
        else:
            self.report({'INFO'}, f"成功合并 {merged_count} 组同材质mesh")
        
        return {'FINISHED'}


class VIEW3D_PT_merge_material_meshes(Panel):
    """UI面板"""
    bl_label = "合并同材质Mesh"
    bl_idname = "VIEW3D_PT_merge_material_meshes"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = "Tool"

    def draw(self, context):
        layout = self.layout
        
        # 获取当前选中的集合
        active_collection = context.view_layer.active_layer_collection.collection
        
        # 集合名称输入
        layout.prop_search(context.scene, "merge_material_collection", 
                          bpy.data, "collections", text="集合")
        
        # 合并按钮
        if context.scene.merge_material_collection:
            op = layout.operator("object.merge_same_material_meshes", 
                               text="合并同材质Mesh")
            op.collection_name = context.scene.merge_material_collection
        else:
            layout.label(text="请选择集合")


# 注册属性
def register():
    bpy.utils.register_class(OBJECT_OT_merge_same_material_meshes)
    bpy.utils.register_class(VIEW3D_PT_merge_material_meshes)
    
    # 添加场景属性
    bpy.types.Scene.merge_material_collection = StringProperty(
        name="Merge Collection",
        description="要合并的集合名称"
    )


def unregister():
    bpy.utils.unregister_class(OBJECT_OT_merge_same_material_meshes)
    bpy.utils.unregister_class(VIEW3D_PT_merge_material_meshes)
    
    # 删除场景属性
    del bpy.types.Scene.merge_material_collection


if __name__ == "__main__":
    register()